package org.dna.metronomo.persistence.impl;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.dna.metronomo.persistence.Activity;
import org.dna.metronomo.persistence.IActivityDAO;
import org.dna.metronomo.persistence.Job;
import org.dna.metronomo.persistence.PersistenceException;

public class IBatisActivityDAO extends IBatisMetronomoDAO
        implements IActivityDAO {

    private static final Logger LOG = Logger.getLogger(IBatisActivityDAO.class);

    public List<Activity> allActivities() throws PersistenceException {
        return executeInSession(new SessionExecutor<List<Activity>>() {

            @SuppressWarnings("unchecked")
            public List<Activity> execute(SqlSession session) throws SQLException {
                return (List<Activity>) session.selectList("ActivityMapper.listAll");
            }
        });
    }

    public void addNewActivity(final Activity activity)
            throws PersistenceException {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {

                session.insert("ActivityMapper.insert", activity);
                LOG.info("Executing ActivityMapper.insert, inserted with " + activity);
                return null;
            }
        });
    }

    public void deleteActivityByExample(final Activity activity) {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {
                if (activity.getJobs() == null || activity.getJobs().isEmpty()) {
                    session.delete("ActivityMapper.deleteByExample", activity);
                } else {
                    Map param = new HashMap();
                    param.put("activity", activity);
                    param.put("status", STATUS_DELETED);
                    session.update("ActivityMapper.updateStatusByExample", param);
                }
                return null;
            }
        });
    }

    public void deleteActivityByID(final int id) {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {
                Activity activity = new QueryByIDExecutor(id).execute(session);
                if (activity == null) {
                    return null;
                }

                if (activity.getJobs() == null || activity.getJobs().isEmpty()) {
                    session.delete("ActivityMapper.deleteByID", activity.getId());
                } else {
                    Map param = new HashMap();
                    param.put("id", id);
                    param.put("status", STATUS_DELETED);
                    session.insert("ActivityMapper.updateStatusByID", param);
                }
                return null;
            }
        });
    }

    public void update(final Activity activity) throws PersistenceException {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {
                session.update("ActivityMapper.update", activity);
                return null;
            }
        });
    }

    public void addJobToActivity(final Job job, final Activity activity)
            throws PersistenceException {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("activity", activity);
                params.put("job", job);
                session.insert("JobMapper.addJobToActivity", params);
                return null;
            }
        });
    }

    public void updateJob(final Job job) throws PersistenceException {
        executeInSession(new SessionExecutor<Void>() {
            public Void execute(SqlSession session) throws SQLException {
                session.insert("JobMapper.update", job);
                return null;
            }
        });
    }

    public List<Activity> queryActivityByExample(final Activity activity)
            throws PersistenceException {
        return executeInSession(new SessionExecutor<List<Activity>>() {

            @SuppressWarnings("unchecked")
            public List<Activity> execute(SqlSession session) throws SQLException {
                return session.selectList("ActivityMapper.queryByExample",
                        activity);
            }
        });
    }

    public Activity queryActivityByID(final int id) {
        return executeInSession(new QueryByIDExecutor(id));
    }

    private static class QueryByIDExecutor implements SessionExecutor<Activity> {
        int id;

        public QueryByIDExecutor(int id) {
            this.id = id;
        }

        @SuppressWarnings("unchecked")
        public Activity execute(SqlSession session) throws SQLException {
            Activity act = (Activity) session.selectOne("ActivityMapper.queryByID",
                    this.id);
            return act;
        }
    }
}
